var Util = require('../Util/Util').Util;
var Animation = require('../Animation').Animation;
var Scale = require('../Util/Scaler').Scale;

exports.SmoothBrowserOptions = Core.Class.subclass({
/** @lends Browser.SmoothBrowserOptions.prototype */	
	classname: 'SmoothBrowserOptions',
	
	/**
	 * @class Options for the smooth browser
	 * Parameters include bounceBackPixels, spacing, browserSize, origin
	 * 
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
	initialize: function() {
		
		this.bounceBackPixels = 10;
		this.spacing = 10;
		this.origin = new Core.Vector(0,0);
		this.browserSize = Util.screenSize(true);
	}
});

exports.SmoothBrowser = Animation.AANode.subclass({
/** @lends Browser.SmoothBrowser.prototype */
    classname: 'SmoothBrowser',
    
	/**
	 * @class A swipable browser
	 * @param {Array} blocks The blocks for the browser
	 * @param {Browser.SmoothBrowserOptions} options The browser options
	 * @constructs The default constructor
	 * @augments Animation.AANode
	 */
    initialize: function(blocks, options, vertical){
    
        this.options = options;
        this.blocks = blocks;
        this.locked = false;
		if (vertical) this.vertical = true;
		else this.vertical = false;
        
		this.setPosition(this.options.origin.clone());
		
        this.touchTarget = new GL2.TouchTarget();
		this.touchTarget.setSize(this.options.browserSize);
		this.touchTarget.setAnchor(new Core.Point(0,0));
		this.touchTarget.setPosition(this.getPosition().clone());
		
        this.scrollTouchHandler = new this.BrowserScrollTouchHandler(this, true);
        this.touchTarget.getTouchEmitter().addListener(this.scrollTouchHandler, this.scrollTouchHandler.onTouch);
        
		for (var i in this.blocks) {
			this.addChild(this.blocks[i]);
		}
		
        this.setContentSizeByBlocks();
        
        this.calculatePositions(this.blocks);
    },
    
	/**
	 * Sets the total size of this browser looking at the blocks
	 * @private
	 */
    setContentSizeByBlocks: function(){
    
        var xSize = 0;
		var ySize = 0;
		if (this.vertical) {
			for (var i in this.blocks) {
	            var block = this.blocks[i];
	            ySize += block.getSize().getHeight();
				if (i != 0) {
					//added to include spacing for centering of browser
					ySize += this.options.spacing;
				}
	        }
			xSize = this.options.browserSize.getWidth();
		} else {
			for (var i in this.blocks) {
	            var block = this.blocks[i];
	            xSize += block.getSize().getWidth();
				if (i != 0) {
					//added to include spacing for centering of browser
					xSize += this.options.spacing;
				}
	        }
			ySize = this.options.browserSize.getHeight();
		}
        
        this.contentSize = new Core.Size(xSize, ySize);
    },
    
	/**
	 * Sets the positions for the specified blocks
	 * @param {Array} blocks The blocks to set the positions of
	 * @private
	 */
    calculatePositions: function(blocks){ // contentSize should be set before this is called
    	var yPos = 0;
		var xPos = 0;
		var blockWidth;
		
    	if (this.vertical) {
			xPos = this.options.browserSize.getWidth() / 2;
			for (var i in blocks) {
	            var block = blocks[i];
	            blockWidth = block.getSize().getHeight();
	            
	            // theres no anchor point to set... do it manually
	            if (yPos == 0) 
	                yPos = blockWidth / 2;
	            
				block.setPosition(xPos, yPos);
	            yPos += blockWidth + this.options.spacing;
	            
	        }
		} else {
			yPos = this.options.browserSize.getHeight() / 2;
			for (var i in blocks) {
	            var block = blocks[i];
	            blockWidth = block.getSize().getWidth();
	            
	            // theres no anchor point to set... do it manually
	            if (xPos == 0) 
	                xPos = blockWidth / 2;
	            
	            //block.setPosition(xPos,yPos);
	            //block.setPosition(xPos, this.options.getYPosition());
				block.setPosition(xPos, yPos);
	            xPos += blockWidth + this.options.spacing;
	            
	        }
		}
    },
    
	/**
	 * Sets whether the browser is locked or not
	 * @param {Object} locked Whether the browser is locked or not
	 */
	setLocked: function(locked) {
		this.locked = locked;
	},
	
	/**
	 * @returns {Core.Vector} The browser's origin
	 */
    getOrigin: function(){
        return this.options.origin;
    },
    
	/**
	 * Enable or disable the browser touching
	 * @param {boolean} enabled Whether the browser is enabled or not
	 */
    setEnabled: function(enabled){
        this.setVisible(enabled);
        this.setTouchable(enabled);
        this.touchTarget.setTouchable(enabled);
    },
    
	/**
	 * Gets the touch target for this browser
	 * @returns {GL2.TouchTarget} The touch target
	 */
    getTouchTarget: function(){
        return this.touchTarget;
    },
    
	/**
	 * Not sure if this is still useful
	 * @param {Object} touch
	 * @private
	 */
    objectForTouch: function(touch){
    
//        for (var i in this.blocks) {
//			
//            var obj = this.blocks[i];
//            if (!obj) continue;
//            
//            var local = obj.screenToLocal(touch.getPosition());
//            
//            //figures out the top left origin, since 0,0 is where the anchorpoint is, we normalize it to the top left origin.
//            var topLeftOrigin = Util.getPositionForAnchorPointGivenValues(new Core.Point(0, 0), obj.getSize(), obj.getAnchor(), new Core.Point(0, 0));
//            var itemRect = new Core.Rect(topLeftOrigin.getX(), topLeftOrigin.getY(), obj.getSize().getWidth(), obj.getSize().getHeight());
//            
//            if (Util.rectContainsPoint(itemRect, local)) {
//                return obj;
//            }
//        }
        
        return null;
    },
    
	/**
	 * Get the browser options
	 * @returns {Browser.SmoothBrowserOptions} The browser options
	 */
    getBrowserOptions: function(){
        return this.options;
    },
    
	/**
	 * Gets the browser content size
	 * @return {Core.Size} the browser content size
	 */
    getContentSize: function(){
        return this.contentSize;
    },
	
	destroy: function($super) {
		for (var i = this._children.length - 1; i >= 0; i--) {
			this._children[i].destroy();
		}
		$super();
	},
    
    $BrowserScrollTouchHandler: Core.MessageListener.subclass({
		
        initialize: function(browser, lockY){
        
            this._browser = browser;
            this._target = browser.getTouchTarget();
            this._snapLeft = false;
            this._snapRight = false;
            this._swipeAccelAnchorX = [];
            this._swipeAccelAnchorY = [];
            this._swipeHistoryCount = 3;
            
            if (typeof lockY == 'undefined') 
                lockY = false;
            
            this._lockY = lockY;
        },
        
        getTouchTarget: function(){
            return this._target;
        },
        
        getWidthForSnapRight: function(){
            var contentWidth = this._browser.options.browserSize.getWidth();
            var windowWidth = Util.screenSize(true).getWidth();
            
            return contentWidth >= windowWidth ? contentWidth - windowWidth : 0;
        },
        
		getHeightForSnapDown: function(){
            var contentHeight = this._browser.options.browserSize.getHeight();
            var windowHeight = Util.screenSize(true).getHeight();
            
            return contentHeight >= windowHeight ? contentHeight - windowHeight : 0;
        },
		
        onTouch: function(touch){
			
            switch (touch.getAction()) {
				
                case touch.Action.Start:
                    
                    NgLogD('smooth browser touch');
					// keeps track of touches
                    if (this._trackingId != touch.getId()) 
					{
						this._previoustouchedBlock = this._touchedBlock;
					}
					else this._previoustouchedBlock = null;
					
					
                    this._trackingId = touch.getId();
                    this._trackingCurrent = touch.getPosition();
                    
					var options = this._browser.options;
//					var yPos = this._trackingCurrent.getY();
//					this._isInYBounds = yPos >= options.getYScreenTopBounds() && yPos <= options.getYScreenBottomBounds();
//					if (!this._isInYBounds) return;
					
					this._browser.stopAllActions();
					
                    var local = this._browser.getParent().screenToLocal(this._trackingCurrent);
                    var current = this._browser.getPosition();
                    
                    this.originalPosition = this._browser.getPosition().clone();
                    
                    //offset of the actual difference between the point of touch and the current position of tilemap
                    this._trackingOffset = new Core.Vector(current.getX() - local.getX(), current.getY() - local.getY());
					
                    // recording swipe data for scrolling
                    for (var i = 0; i < this._swipeHistoryCount; i++) {
                        this._swipeAccelAnchorX[i] = touch.getPosition().getX();
                        this._swipeAccelAnchorY[i] = touch.getPosition().getY();
                    }
                    this._moveCount = 0;
                    
                    this._touchedBlock = this._browser.objectForTouch(touch);
                    if (this._touchedBlock) {
                        NgLogD("Touched Block")
                        if (this._touchedBlock.classname == 'SmoothBrowserButtonBlock') {
                            this._touchedBlock.activate();
                        }
                    }
                    
                    return true;
                case touch.Action.End:
                   	// kills previous item touched
					if (this._trackingId != touch.getId()) 
					{
						if (this._previoustouchedBlock)
							this._previoustouchedBlock.inactivate();
                        return;
					}
					
					//if (!this._isInYBounds) return;
					
                    this._trackingId = NaN;
                    
					for (var i = 0; i < this._browser.blocks.length; i++) {
						if (touch.getIsInside(this._browser.blocks[i].getTouchTarget())) {
							if (typeof this._browser.blocks[i].touchedBlock != 'undefined') {
								this._browser.blocks[i].touchedBlock();
								return;
							} 
						}
					}
//                    if (this._touchedBlock) {
//                        if (typeof this._touchedBlock.touched != 'undefined') 
//                            this._touchedBlock.touched();
//                    }
//                    else {
                    
						if (this._browser.locked) return;
					
                        var origin = this._browser.options.origin;
                        var distance = 0;
						if (this._browser.vertical) distance = this.getHeightForSnapDown();
						else distance = this.getWidthForSnapRight();
                        
                        this._moveCount++;
                        var mod = this._moveCount % this._swipeHistoryCount;
                        var swipeDistance;
						if (this._browser.vertical) swipeDistance = touch.getPosition().getY() - this._swipeAccelAnchorY[mod]; 
						else swipeDistance = touch.getPosition().getX() - this._swipeAccelAnchorX[mod];
                        
                        // Start Snap Code
                        if (this._snapLeft) {
                        
                            NgLogD("End: Snap Left");
							var pos = origin.clone();
							var slideAction = new Animation.AAEaseOut(new Animation.AAMoveTo(pos, 0.3), 2);
							this._browser.runAction(slideAction);
							
                            return;
                        }
                        else  if (this._snapRight) {
                            
                            NgLogD("End: Snap Right");
							var pos;
							if (this._browser.vertical) pos = new Core.Vector(origin.getX(), origin.getY() - distance);
							else pos = new Core.Vector(origin.getX() - distance, origin.getY());
							var slideAction = new Animation.AAEaseOut(new Animation.AAMoveTo(pos, 0.3), 2);
							this._browser.runAction(slideAction);
							
                           	return;
                        }
                        this._snapLeft = false;
                        this._snapRight = false;
                        // End Snap Code
                        
                        var accelModPositon, accelDuration, easeOutRate;
                        if (Math.abs(swipeDistance) > Scale.ios.width(80)) {
                            if (this._browser.vertical) accelModPosition = new Core.Vector(0, swipeDistance * 7);
							else accelModPosition = new Core.Vector(swipeDistance * 7, 0);
                            accelDuration = 1.5;
                            easeOutRate = 3;
                        }
                        else if (Math.abs(swipeDistance) > Scale.ios.width(20)) {
							if (this._browser.vertical) accelModPosition = new Core.Vector(0, swipeDistance * 4);
							else accelModPosition = new Core.Vector(swipeDistance * 4, 0);
                            accelDuration = 1;
                            easeOutRate = 2;
                        }
                        else {
                            if (this._browser.vertical) accelModPosition = new Core.Vector(0, swipeDistance * 2);
							else accelModPosition = new Core.Vector(swipeDistance * 2, 0);
                            accelDuration = 0.3;
                            easeOutRate = 1;
                        }
                        
                        var newPosition = new Core.Vector(accelModPosition.getX() + this._browser.getPosition().getX(), accelModPosition.getY() + this._browser.getPosition().getY());
                        
                        // Check for snapback first
                        var bounceBackPixels = this._browser.options.bounceBackPixels;
                        if ((this._browser.vertical ? newPosition.getY() : newPosition.getX()) >= (this._browser.vertical ? origin.getY() : origin.getX()) + bounceBackPixels) {
                        
                            NgLogD("End: SnapBack Left");
							var pos = origin.clone();
							this._browser.runAction(new Animation.AAMoveTo(pos, 0.3));
                        }
                        else if ((this._browser.vertical ? newPosition.getY() : newPosition.getX()) <= (this._browser.vertical ? origin.getY() : origin.getX()) - distance - bounceBackPixels) {
                            
                            NgLogD("End: SnapBack Right");
							var pos;
							if (this._browser.vertical) pos = new Core.Vector(origin.getX(), origin.getY() - distance);
							else pos = new Core.Vector(origin.getX() - distance, origin.getY());
                            this._browser.runAction(new Animation.AAMoveTo(pos, 0.3));
                        }
                        else {
							
							var moveVect;
							if (this._browser.vertical) moveVect = new Core.Vector(accelModPosition.getX(), 0);
							else moveVect = new Core.Vector(0, accelModPosition.getY());
							var slideAction = new Animation.AAEaseOut(new Animation.AAMoveBy(moveVect, accelDuration), easeOutRate);
							this._browser.runAction(slideAction);
                        }
//                    }
                    
                    break;
                case touch.Action.Move:
					// kills previous item touched
					if (this._trackingId != touch.getId()) 
					{
						if (this._previoustouchedBlock)
							this._previoustouchedBlock.inactivate();
                        return;
					}
					//if (!this._isInYBounds) return;
					
                    var change = 0;
					if (this._browser.vertical) change = Math.abs(this._trackingCurrent.getY() - touch.getPosition().getY());
					else change = Math.abs(this._trackingCurrent.getX() - touch.getPosition().getX());
                    if (change < Scale.ios.width(10) && this._touchedBlock) {
                        return;
                    }
                    
                    if (this._touchedBlock && this._touchedBlock.classname == 'SmoothBrowserButtonBlock') {
                        this._touchedBlock.inactivate();
                    }
                    //if it moved kill the touchedobject
                    this._touchedBlock = null;
                    
					if (this._browser.locked) return;
					
                    this._trackingCurrent = touch.getPosition();
                    var current = this._browser.getParent().screenToLocal(this._trackingCurrent);
                    var offset = this._trackingOffset;
                    
                    this._moveCount++;
                    
                    var mod = this._moveCount % this._swipeHistoryCount;
                    this._swipeAccelAnchorX[mod] = touch.getPosition().getX();
                    this._swipeAccelAnchorY[mod] = touch.getPosition().getY();
                    
                    var newPosition;
					if (this._browser.vertical) newPosition = new Core.Vector(this._browser.getPosition().getX(), current.getY() + offset.getY());
					else newPosition = new Core.Vector(current.getX() + offset.getX(), this._browser.getPosition().getY());
                    
                    // Start Snap Code
                    var distance = 0;
					if (this._browser.vertical) distance = this.getHeightForSnapDown();
					else distance = this.getWidthForSnapRight();
                    var origin = this._browser.options.origin;
                    var bounceBackPixels = this._browser.options.bounceBackPixels;
					
                    if ((this._browser.vertical ? newPosition.getY() : newPosition.getX()) >= (this._browser.vertical ? origin.getY() : origin.getX()) + bounceBackPixels) {
                    	
                        NgLogD("Move: Snap Left");
                        this._snapLeft = true;
                    	//newPosition = new Core.Vector(current.getX() + (offset.getX() / 2), this._browser.getPosition().getY());
                    }
                    else if ((this._browser.vertical ? newPosition.getY() : newPosition.getX()) <= (this._browser.vertical ? origin.getY() : origin.getX()) - distance - bounceBackPixels) {
                        
                        NgLogD("Move: Snap Right");
                        this._snapRight = true;
                        //newPosition = new Core.Vector(current.getX() + (offset.getX() / 2), this._browser.getPosition().getY());
                    }
                    else {
                        this._snapLeft = false;
                        this._snapRight = false;
                    }
                    // End Snap Code
					
                    this._browser.setPosition(newPosition);
                    
                    break;
            }
        }
    }),
});
